//#include <windows.h>
#include <GL/glut.h>
#include <math.h>
#include <stdlib.h>

#define PI 3.1415926535
class CPoint2D {
public:
	float x, y;
};

float My2DMatrix[3][3];

void Mutiply(float M[3][3], float Out[3][3]) {
	float temp[3][3];
	temp[0][0] = M[0][0]*Out[0][0] + M[0][1]*Out[1][0] + M[0][2]*Out[2][0];
	temp[0][1] = M[0][0]*Out[0][1] + M[0][1]*Out[1][1] + M[0][2]*Out[2][1];
	temp[0][2] = M[0][0]*Out[0][2] + M[0][1]*Out[1][2] + M[0][2]*Out[2][2];

	temp[1][0] = M[1][0]*Out[0][0] + M[1][1]*Out[1][0] + M[1][2]*Out[2][0];
	temp[1][1] = M[1][0]*Out[0][1] + M[1][1]*Out[1][1] + M[1][2]*Out[2][1];
	temp[1][2] = M[1][0]*Out[0][2] + M[1][1]*Out[1][2] + M[1][2]*Out[2][2];

	temp[2][0] = M[2][0]*Out[0][0] + M[2][1]*Out[1][0] + M[2][2]*Out[2][0];
	temp[2][1] = M[2][0]*Out[0][1] + M[2][1]*Out[1][1] + M[2][2]*Out[2][1];
	temp[2][2] = M[2][0]*Out[0][2] + M[2][1]*Out[1][2] + M[2][2]*Out[2][2];

	for(int i=0; i<3; i++) {
		for(int j=0; j<3; j++) {
			Out[i][j] = temp[i][j];
		}
	}
}

void ScalingMatrix(float sx, float sy, float M[3][3]) {
	float temp[3][3] = {
		{sx, 0.0, 0.0},
		{0.0, sy, 0.0},
		{0.0, 0.0, 1.0}
	};
	for(int i=0; i<3; i++) {
		for(int j=0; j<3; j++) {
			M[i][j] = temp[i][j];
		}
	}
}

void Scale(float sx, float sy) {
	float M[3][3];
	ScalingMatrix(sx, sy, M);

	Mutiply(M, My2DMatrix);
}

void RotationMatrix(float theta, float M[3][3]) {
	float temp[3][3] = {
		{cos(theta), -sin(theta), 0},
		{sin(theta), cos(theta), 0},
		{0.0, 0.0, 1.0}
	};
	for(int i=0; i<3; i++) {
		for(int j=0; j<3; j++) {
			M[i][j] = temp[i][j];
		}
	}
}

void Rotate(float theta) {
	float M[3][3];
	RotationMatrix(theta, M);

	Mutiply(M, My2DMatrix);
}

void TranslationMatrix(float tx, float ty, float M[3][3]) {
	float temp[3][3] = {
		{1.0, 0.0, tx},
		{0.0, 1.0, ty},
		{0.0, 0.0, 1.0}
	};
	for(int i=0; i<3; i++) {
		for(int j=0; j<3; j++) {
			M[i][j] = temp[i][j];
		}
	}
}


void Translate(float tx, float ty) {
	float M[3][3];
	TranslationMatrix(tx, ty, M);

	Mutiply(M, My2DMatrix);
}

void Transform2DPoint(CPoint2D *p, float M[3][3], CPoint2D * q) {
	float x = p->x, y = p->y;
	q->x = M[0][0]*x + M[0][1]*y + M[0][2]*1;
	q->y = M[1][0]*x + M[1][1]*y + M[1][2]*1;
}

void IdentityMatrix(float M[3][3]) {
	float temp[3][3] = {
		{1.0, 0.0, 0.0},
		{0.0, 1.0, 0.0},
		{0.0, 0.0, 1.0}
	};

	for(int i=0; i<3; i++) {
		for(int j=0; j<3; j++) {
			M[i][j] = temp[i][j];
		}
	}
}

void init(void) {
	glClearColor(0.0, 0.0, 0.5, 0.0);
	IdentityMatrix(My2DMatrix);
}

void display(void) {
	static CPoint2D MyObject[] = {
		{0.0, 63.0},
		{-60.0, 20.0}, {-60.0, -20.0},
		{60.0, -20.0}, {60.0, 20.0}
	};
	CPoint2D pp;
	int i;

	glClear(GL_COLOR_BUFFER_BIT);
	glColor3f(1.0, 0.0, 0.0);

	glBegin(GL_POLYGON);
	for(i=0; i<5; ++i) {
		Transform2DPoint(MyObject+i, My2DMatrix, &pp);
		glVertex2f(pp.x, pp.y);
	}
	glEnd();

	glutSwapBuffers();
}

void reshape(int w, int h) {
	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(-100, 100, -100, 100);
}

void keyboard(unsigned char key, int x, int y) {
	switch(key) {
		case 27: exit(0);
	}
}

void special_key(int key, int x, int y) {
	switch(key) {
	case GLUT_KEY_LEFT:
		Translate(-5.0, 0.0);
		glutPostRedisplay();
		break;
	case GLUT_KEY_RIGHT:
		Translate(5.0, 0.0);
		glutPostRedisplay();
		break;
	case GLUT_KEY_DOWN:
		Translate(0.0, -5.0);
		glutPostRedisplay();
		break;
	case GLUT_KEY_UP:
		Translate(0.0, 5.0);
		glutPostRedisplay();
		break;
	case GLUT_KEY_PAGE_UP:
		//Rotate(float theta);
		Rotate(1.57);
		glutPostRedisplay();
		break;
	case GLUT_KEY_PAGE_DOWN:
		Rotate(1.57);
		//Rotate(float theta);
		glutPostRedisplay();
		break;
	case GLUT_KEY_HOME:
		// Scale(float sx, float sy);
		Scale(0.5, 0.5);
		glutPostRedisplay();
		break;
	case GLUT_KEY_END:
		// Scale(float sx, float sy);
		Scale(2, 2);
		glutPostRedisplay();
		break;

	}
}

int main(int argc, char * argv[]) {
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
	glutInitWindowSize(500, 500);
	glutInitWindowPosition(100, 100);
	glutCreateWindow("Test 2D Transformation");

	init();

	glutDisplayFunc(display);
	glutReshapeFunc(reshape);
	glutKeyboardFunc(keyboard);
	glutSpecialFunc(special_key);

	glutMainLoop();

	return 0;
}